package cn.cycleif.component.redis;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.json.JSONUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * @Date: 25/1/19-23:25
 * @Desc:
 */
@Component
public class RedisCacheImpl implements RedisCache {

  @Autowired
  private StringRedisTemplate srt;

  public static final long DEFAULT_EXPIRE = 60 * 60 * 24L;
  public static final long NOT_EXPIRE     = -1;

  @Override
  public void set(String key, Object value, long expire) {
    srt.opsForValue().set(key, toJson(value));
    if (expire != NOT_EXPIRE) srt.expire(key, expire, TimeUnit.SECONDS);
  }

  @Override
  public void expire(String key, long expire, TimeUnit unit) {
    srt.expire(key, expire, unit);
  }

  @Override
  public void set(String key, Object value) {
    set(key, value, DEFAULT_EXPIRE);
  }

  @Override
  public <T> T get(String key, Class<T> clazz, long expire) {
    String value = srt.opsForValue().get(key);
    if (expire != NOT_EXPIRE) srt.expire(key, expire, TimeUnit.SECONDS);
    return isStrNull(value) ? null : fromJson(value, clazz);
  }

  @Override
  public <T> T get(String key, Class<T> clazz) {
    return get(key, clazz, NOT_EXPIRE);
  }

  @Override
  public <T> T get(String key, Class<T> clazz, Supplier<T> supplier, long ttl) {
    T t = get(key, clazz);
    if (null == t) {
      T ts = supplier.get();
      set(key, ts, ttl);
      return ts;
    }
    return t;
  }

  @Override
  public String get(String key, long expire) {
    String value = srt.opsForValue().get(key);
    if (expire != NOT_EXPIRE) srt.expire(key, expire, TimeUnit.SECONDS);
    return value;
  }

  @Override
  public String get(String key) {
    return get(key, NOT_EXPIRE);
  }

  @Override
  public void delete(String key) {
    srt.delete(key);
  }

  @Override
  public void delete(List<String> keys) {
    srt.delete(keys);
  }

  public Boolean hasKey(String key) {
    return srt.hasKey(key);
  }

  @Override
  public long getExpire(String key) {
    Long exp = srt.getExpire(key);
    return null == exp ? -1 : exp;
  }

  @Override
  public Integer getHyperLog(String key) {
    return srt.opsForHyperLogLog().size(key).intValue();
  }

  @Override
  public Integer hyperLogAdd(String key, String value) {
    srt.opsForHyperLogLog().add(key, value);
    return srt.opsForHyperLogLog().size(key).intValue();
  }

  public Long sAdd(String key, Object value) {
    return srt.opsForSet().add(key, toJson(value));
  }

  public Long sRem(String key, Object value) {
    return srt.opsForSet().remove(key, value);
  }

  public Boolean sIsMember(String key, Object value) {
    return srt.opsForSet().isMember(key, value);
  }

  public Set<String> sMember(String key) {
    return srt.opsForSet().members(key);
  }

  public Long sSize(String key) {
    return srt.opsForSet().size(key);
  }

  public void hSet(String key, String hashKey, Object value) {
    srt.opsForHash().put(key, hashKey, toJson(value));
  }

  public Long hDel(String key, String hashKey) {
    return srt.opsForHash().delete(key, hashKey);
  }

  public Boolean hExists(String key, String hashKey) {
    return srt.opsForHash().hasKey(key, hashKey);
  }

  public Long hSize(String key) {
    return srt.opsForHash().size(key);
  }

  public Set<Object> hKeys(String key) {
    return srt.opsForHash().keys(key);
  }

  /**
   * 需要手动反序列化
   *
   * @param key
   * @return
   */
  public List<Object> hVals(String key) {
    return srt.opsForHash().values(key);
  }

  public Object hGet(String key, String hashKey) {
    return srt.opsForHash().get(key, hashKey);
  }

  public Long hIncrBy(String key, String hashKey, long delta) {
    return srt.opsForHash().increment(key, hashKey, delta);
  }

  private boolean isStrNull(String str) {
    return CharSequenceUtil.isEmpty(str);
  }

  /**
   * Object转成JSON数据
   */
  private String toJson(Object object) {
    if (object instanceof Integer || object instanceof Long || object instanceof Float || object instanceof Double || object instanceof Boolean || object instanceof String) {
      return String.valueOf(object);
    }
    return JSONUtil.toJsonStr(object);
  }

  /**
   * JSON数据，转成Object
   */
  private <T> T fromJson(String json, Class<T> clazz) {
    return JSONUtil.toBean(json, clazz);
  }
}
